import static org.junit.Assert.assertSame;
import static org.junit.Assert.fail;

import java.io.File;
import java.io.IOException;

import model.BasicParameter;
import model.NoSuchDirectoryException;
import model.cnf.CNF;
import model.cnf.FileCNF;
import model.preprocessor.PreProcessorFactory;
import model.preprocessor.PreProcessorResultStatus;
import model.session.CNFUse;
import model.session.ExecutableSessionBlock;
import model.session.ExecutionStatus;
import model.session.PreprocessorExecutionBlock;
import model.session.SolverExecutionBlock;
import model.solver.SolverFactory;
import model.solver.SolverResultStatus;

import org.junit.Test;

import controller.IExecutionListener;
import controller.preprocessor.PreProcessor;
import controller.solver.Solver;

/**
 * 
 */

/**
 * @author GRONOWSKI Stephane svan001@aol.com
 * 
 *         igsat 2010
 * 
 */
public class TestExecutableSessionBlock {

	// private CNFUse cnfuse;
	// private CNF cnf;
	private String				cnflonguepath	= "./tstcnf/longue.cnf";
	private String				cnfsatpath		= "./tstcnf/sat.cnf";
	private String				cnfunsatpath	= "./tstcnf/unsat.cnf";
	private String				cnfcourpath		= "./tstcnf/cour.cnf";
	private String				cnfcourtepath	= "./tstcnf/courte.cnf";
	private String				out				= "./cnf/newcnf.cnf";

	private File				dirpreproc		= new File("./preproc");
	private File				dirsolveur		= new File("./solveur");

	private PreProcessorFactory	preprocfactory	= new PreProcessorFactory(dirpreproc);
	private SolverFactory		solverfactory	= new SolverFactory(dirsolveur);

	private CNFUse getCNFUse(String path) {
		CNFUse cnfuse;
		CNF cnf;

		try
		{
			cnf = new FileCNF(path);
		} catch (IOException e)
		{
			e.printStackTrace();
			return null;
		}

		cnfuse = new CNFUse(cnf);
		return cnfuse;
	}

	@Test
	public void testSolverExecutionNoListener() {
		CNFUse cnfuse = getCNFUse(cnfsatpath);
		if (cnfuse == null)
			fail("problem creating cnf");

		Solver solver = null;
		try
		{
			solver = solverfactory.createMiniSatSolver();
		} catch (NoSuchDirectoryException e)
		{
			e.printStackTrace();
			fail("problem creating solver");
			return;
		}

		SolverExecutionBlock block = new SolverExecutionBlock(cnfuse, ExecutionStatus.READY, solver, null);
		block.setCnf(cnfuse.getCnf());
		block.run();

		try
		{

			Thread.sleep(200);
		} catch (InterruptedException e)
		{
			e.printStackTrace();
			fail("problem wait");
			return;
		}

		assertSame("solver block run without listener", block.getStatus(), ExecutionStatus.PROBLEM);
	}

	@Test
	public void testSolverExecutionNoCNF() {
		CNFUse cnfuse = getCNFUse(cnfsatpath);
		if (cnfuse == null)
			fail("problem creating cnf");

		Solver solver = null;
		try
		{
			solver = solverfactory.createMiniSatSolver();
		} catch (NoSuchDirectoryException e)
		{
			e.printStackTrace();
			fail("problem creating solver");
			return;
		}

		SolverExecutionBlock block = new SolverExecutionBlock(cnfuse, ExecutionStatus.READY, solver, null);
		IExecutionListener listener = new IExecutionListener() {

			@Override
			public void reportEndExec(ExecutableSessionBlock exec) {
			}
		};
		block.setListener(listener);

		block.run();

		try
		{

			Thread.sleep(200);
		} catch (InterruptedException e)
		{
			e.printStackTrace();
			fail("problem wait");
			return;
		}

		assertSame("solver block run without cnf", block.getStatus(), ExecutionStatus.PROBLEM);
	}

	@Test
	public void testSolverExecutionBlockWork() {
		CNFUse cnfuse = getCNFUse(cnfsatpath);
		if (cnfuse == null)
			fail("problem creating cnf");

		Solver solver = null;
		try
		{
			solver = solverfactory.createMiniSatSolver();
		} catch (NoSuchDirectoryException e)
		{
			e.printStackTrace();
			fail("fail creating solver");
			return;
		}

		SolverExecutionBlock block = new SolverExecutionBlock(cnfuse, ExecutionStatus.READY, solver, null);

		IExecutionListener listener = new IExecutionListener() {

			@Override
			public void reportEndExec(ExecutableSessionBlock exec) {
				SolverExecutionBlock solv = (SolverExecutionBlock) exec;

				assertSame("solver block status is not finish", ExecutionStatus.FINISH, solv.getStatus());
				assertSame("solver result status after sat cnf is not sat", SolverResultStatus.SATISFIABLE, solv.getRes().getStatus());

			}
		};
		block.setListener(listener);
		block.setCnf(cnfuse.getCnf());

		block.run();
	}

	@Test
	public void testSolverExecutionBlockStop() {
		CNFUse cnfuse = getCNFUse(cnflonguepath);
		if (cnfuse == null)
			fail("problem creating cnf");

		Solver solver = null;
		try
		{
			solver = solverfactory.createMiniSatSolver();
		} catch (NoSuchDirectoryException e)
		{
			e.printStackTrace();
			fail("fail creting solver");
			return;
		}

		SolverExecutionBlock block = new SolverExecutionBlock(cnfuse, ExecutionStatus.READY, solver, null);

		IExecutionListener listener = new IExecutionListener() {

			@Override
			public void reportEndExec(ExecutableSessionBlock exec) {
				SolverExecutionBlock solv = (SolverExecutionBlock) exec;

				assertSame("solver block status after stop is not finish", ExecutionStatus.FINISH, solv.getStatus());
				assertSame("solver result status after stop is not stop", SolverResultStatus.STOP, solv.getRes().getStatus());

			}
		};
		block.setListener(listener);
		block.setCnf(cnfuse.getCnf());

		Thread t = new Thread(block);
		t.start();

		block.stopExecution();
	}

	@Test
	public void testSolverExecutionBlockProblem() {
		CNFUse cnfuse = getCNFUse(cnfsatpath);
		if (cnfuse == null)
			fail("problem creating cnf");

		Solver solver = null;
		try
		{
			solver = solverfactory.createMiniSatSolver();
		} catch (NoSuchDirectoryException e)
		{
			e.printStackTrace();
			fail("fail creating solver");
			return;
		}

		// wrong delay shoul be a illegal solver argument exception
		solver.getSolverParameter().setTimeOut(BasicParameter.MIN_DELAY - 1);

		SolverExecutionBlock block = new SolverExecutionBlock(cnfuse, ExecutionStatus.READY, solver, null);

		IExecutionListener listener = new IExecutionListener() {

			@Override
			public void reportEndExec(ExecutableSessionBlock exec) {
				SolverExecutionBlock solv = (SolverExecutionBlock) exec;

				assertSame("solver block status after problem is not finish", ExecutionStatus.PROBLEM, solv.getStatus());

			}
		};
		block.setListener(listener);
		block.setCnf(cnfuse.getCnf());

		block.run();
	}

	@Test
	public void testPreprocessorExecutionNoListener() {
		CNFUse cnfuse = getCNFUse(cnfsatpath);
		if (cnfuse == null)
			fail("problem creating cnf");

		PreProcessor preproc = null;
		try
		{
			preproc = preprocfactory.createSatellitePreProcessor();
		} catch (NoSuchDirectoryException e)
		{
			e.printStackTrace();
			fail("problem creating preprocessor");
			return;
		}

		preproc.getPreProcessorParameter().setOut(out);
		PreprocessorExecutionBlock block = new PreprocessorExecutionBlock(cnfuse, ExecutionStatus.READY, preproc, null);
		block.setCnf(cnfuse.getCnf());

		block.run();

		try
		{
			Thread.sleep(300);
		} catch (InterruptedException e)
		{
			e.printStackTrace();
			fail("problem wait");
			return;
		}

		assertSame("preprocessor block run without listener", block.getStatus(), ExecutionStatus.PROBLEM);
	}

	@Test
	public void testPreprocessorExecutionNoCNF() {
		CNFUse cnfuse = getCNFUse(cnfsatpath);
		if (cnfuse == null)
			fail("problem creating cnf");

		PreProcessor preproc = null;
		try
		{
			preproc = preprocfactory.createSatellitePreProcessor();
		} catch (NoSuchDirectoryException e)
		{
			e.printStackTrace();
			fail("problem creating preprocessor");
			return;
		}

		preproc.getPreProcessorParameter().setOut(out);
		PreprocessorExecutionBlock block = new PreprocessorExecutionBlock(cnfuse, ExecutionStatus.READY, preproc, null);
		IExecutionListener listener = new IExecutionListener() {

			@Override
			public void reportEndExec(ExecutableSessionBlock exec) {
			}
		};
		block.setListener(listener);

		block.run();

		try
		{

			Thread.sleep(200);
		} catch (InterruptedException e)
		{
			e.printStackTrace();
			fail("problem wait");
			return;
		}

		assertSame("preproc block run without cnf", block.getStatus(), ExecutionStatus.PROBLEM);
	}

	@Test
	public void testPreprocessorExecutionBlockWork() {
		CNFUse cnfuse = getCNFUse(cnfunsatpath);
		if (cnfuse == null)
			fail("problem creating cnf");

		PreProcessor preproc = null;
		try
		{
			preproc = preprocfactory.createSatellitePreProcessor();
		} catch (NoSuchDirectoryException e)
		{
			e.printStackTrace();
			fail("problem creating preprocessor");
			return;
		}

		preproc.getPreProcessorParameter().setOut(out);
		PreprocessorExecutionBlock block = new PreprocessorExecutionBlock(cnfuse, ExecutionStatus.READY, preproc, null);

		IExecutionListener listener = new IExecutionListener() {

			@Override
			public void reportEndExec(ExecutableSessionBlock exec) {
				PreprocessorExecutionBlock preproc = (PreprocessorExecutionBlock) exec;

				assertSame("preprocessor block status is not finish", ExecutionStatus.FINISH, preproc.getStatus());
				assertSame("preproc result status after unsat cnf is not unsat", PreProcessorResultStatus.UNSATISFIABLE, preproc.getRes()
						.getStatus());

			}
		};
		block.setListener(listener);
		block.setCnf(cnfuse.getCnf());

		block.run();
	}

	@Test
	public void testPreprocessorExecutionBlockStop() {
		CNFUse cnfuse = getCNFUse(cnflonguepath);
		if (cnfuse == null)
			fail("problem creating cnf");

		PreProcessor preproc = null;
		try
		{
			preproc = preprocfactory.createSatellitePreProcessor();
		} catch (NoSuchDirectoryException e)
		{
			e.printStackTrace();
			fail("problem creating preprocessor");
			return;
		}

		preproc.getPreProcessorParameter().setOut(out);
		PreprocessorExecutionBlock block = new PreprocessorExecutionBlock(cnfuse, ExecutionStatus.READY, preproc, null);

		IExecutionListener listener = new IExecutionListener() {

			@Override
			public void reportEndExec(ExecutableSessionBlock exec) {
				PreprocessorExecutionBlock preproc = (PreprocessorExecutionBlock) exec;

				assertSame("preprocessor block status after stop is not finish", ExecutionStatus.FINISH, preproc.getStatus());
				assertSame("preprocessor result status after stop is not stop", PreProcessorResultStatus.STOP, preproc.getRes().getStatus());

			}
		};
		block.setListener(listener);
		block.setCnf(cnfuse.getCnf());

		Thread t = new Thread(block);
		t.start();

		block.stopExecution();
	}

	@Test
	public void testPreprocExecutionBlockProblem() {
		CNFUse cnfuse = getCNFUse(cnfsatpath);
		if (cnfuse == null)
			fail("problem creating cnf");

		PreProcessor preproc = null;
		try
		{
			preproc = preprocfactory.createSatellitePreProcessor();
		} catch (NoSuchDirectoryException e)
		{
			e.printStackTrace();
			fail("problem creating preprocessor");
			return;
		}

		preproc.getPreProcessorParameter().setOut(out);
		PreprocessorExecutionBlock block = new PreprocessorExecutionBlock(cnfuse, ExecutionStatus.READY, preproc, null);

		// wrong delay shoul be a illegal solver argument exception
		preproc.getPreProcessorParameter().setTimeOut(BasicParameter.MIN_DELAY - 1);

		IExecutionListener listener = new IExecutionListener() {

			@Override
			public void reportEndExec(ExecutableSessionBlock exec) {
				PreprocessorExecutionBlock preproc = (PreprocessorExecutionBlock) exec;

				assertSame("preproc block status after problem is not problem", ExecutionStatus.PROBLEM, preproc.getStatus());

			}
		};
		block.setListener(listener);
		block.setCnf(cnfuse.getCnf());

		block.run();
	}
}
